package com.kantboot.business.water.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.kantboot.business.water.balance.BusWaterBalanceService;
import com.kantboot.business.water.domain.dto.BusWaterGoodsOrderSearchDTO;
import com.kantboot.business.water.domain.dto.BusWaterGoodsOrderSearchOfAdminDTO;
import com.kantboot.business.water.domain.dto.BusWaterGoodsOrderSearchOfManageDTO;
import com.kantboot.business.water.domain.dto.GoodsGenPayOrderDTO;
import com.kantboot.business.water.domain.entity.BusWaterGoods;
import com.kantboot.business.water.domain.entity.BusWaterGoodsOrder;
import com.kantboot.business.water.domain.entity.BusWaterLiftingPoint;
import com.kantboot.business.water.domain.entity.BusWaterVip;
import com.kantboot.business.water.domain.vo.CountOfGoodsOrderVO;
import com.kantboot.business.water.domain.vo.OrderMoneyVO;
import com.kantboot.business.water.domain.vo.OrderUuidVO;
import com.kantboot.business.water.repository.BusWaterOrderRepository;
import com.kantboot.business.water.service.IBusWaterGoodsOrderService;
import com.kantboot.business.water.service.IBusWaterGoodsService;
import com.kantboot.business.water.service.IBusWaterLiftingPointService;
import com.kantboot.business.water.service.IBusWaterVipService;
import com.kantboot.functional.pay.order.domian.dto.GeneratePayOrderDTO;
import com.kantboot.functional.pay.order.domian.entity.FunctionalPayOrder;
import com.kantboot.functional.pay.order.service.IFunctionalPayOrderService;
import com.kantboot.system.user.service.ISysUserBalanceService;
import com.kantboot.system.user.service.IUserSelfService;
import com.kantboot.util.common.exception.BaseException;
import com.kantboot.util.core.param.PageParam;
import com.kantboot.util.core.redis.RedisUtil;
import com.kantboot.util.core.result.PageResult;
import jakarta.annotation.Resource;
import lombok.extern.log4j.Log4j2;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 提水点服务实现
 */
@Log4j2
@Service
public class BusWaterGoodsOrderServiceImpl
        implements IBusWaterGoodsOrderService {

    @Resource
    private BusWaterOrderRepository repository;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private IBusWaterVipService vipService;

    @Resource
    private IUserSelfService userSelfService;

    @Resource
    private BusWaterBalanceService balanceService;

    @Resource
    private IFunctionalPayOrderService functionalPayOrderService;

    @Resource
    private IBusWaterGoodsService goodsService;

    @Resource
    private IBusWaterLiftingPointService liftingPointService;

    @Resource
    private ISysUserBalanceService sysUserBalanceService;


    @Override
    public OrderMoneyVO getDiscountPriceByVipId(Long vipId, BigDecimal money) {
        BusWaterVip byId = vipService.getById(vipId);
        OrderMoneyVO orderMoneyVO = new OrderMoneyVO();
        if (byId == null) {
            // 如果没有vip信息则不打折
            // 原金额
            orderMoneyVO.setOriginalMoney(money);
            // 折扣减免金额
            orderMoneyVO.setDiscountMoney(BigDecimal.ZERO);
            // 支付金额
            orderMoneyVO.setPayMoney(money);
            return orderMoneyVO;
        }
        BigDecimal multiply = money.multiply(byId.getDiscount());
        // 则扣减免金额
        BigDecimal subtract = money.subtract(multiply);


        orderMoneyVO = new OrderMoneyVO()
                .setOriginalMoney(money)
                .setDiscountMoney(subtract)
                .setPayMoney(multiply);
        return orderMoneyVO;
    }

    @Override
    public OrderMoneyVO getDiscountPriceByUserId(Long userId, BigDecimal money) {
        BusWaterVip byUserId = vipService.getByUserId(userId);
        if (byUserId == null) {
            // 如果没有vip信息则不打折
            return new OrderMoneyVO()
                    .setOriginalMoney(money)
                    .setDiscountMoney(BigDecimal.ZERO)
                    .setPayMoney(money);
        }
        // 根据用户id获取用户当月剩余额度
        BigDecimal monthQuotaByUserId = balanceService.getMonthQuotaByUserId(userId);

        if (monthQuotaByUserId.compareTo(BigDecimal.ZERO) <= 0) {
            // 如果当月剩余额度小于等于0则不打折
            return new OrderMoneyVO()
                    .setOriginalMoney(money)
                    .setDiscountMoney(BigDecimal.ZERO)
                    .setPayMoney(money);
        }
        // 获取money打折后的金额，乘法，保持精度2位
        BigDecimal payMoney = money.multiply(byUserId.getDiscount()).setScale(2, BigDecimal.ROUND_HALF_UP);
        // 则扣减免金额
        BigDecimal subtract = money.subtract(payMoney);
        // 如果减免金额大于当月剩余额度，则支付金额为原价减去当月剩余额度
        if (subtract.compareTo(monthQuotaByUserId) > 0) {
            payMoney = money.subtract(monthQuotaByUserId);
        }

        log.info("用户id为{}，原价：{}，折扣：{}，当月剩余额度：{}，减免了金额{}，支付金额为{}",userId, money,byUserId.getDiscount(), monthQuotaByUserId, money.subtract(payMoney), payMoney);

        return new OrderMoneyVO()
                .setOriginalMoney(money)
                .setDiscountMoney(subtract)
                .setPayMoney(payMoney);
    }

    @Override
    public OrderMoneyVO getDiscountPriceBySelf(BigDecimal money) {
        return getDiscountPriceByUserId(userSelfService.getSelfId(), money);
    }

    @Override
    public OrderMoneyVO getDiscountPriceByUserIdAndGoodsId(Long userId, Long goodsId,Long goodsNumber) {
        // 将价格*数量
        BigDecimal money = goodsService.getById(goodsId).getSalePrice().multiply(BigDecimal.valueOf(goodsNumber));

        // 根据用户id获取订单折扣价格
        return getDiscountPriceByUserId(userId, money);
    }

    @Override
    public OrderMoneyVO getDiscountPriceBySelfAndGoodsIdAndGoodsNumber(Long goodsId,Long goodsNumber) {
        OrderMoneyVO orderMoneyVO = getDiscountPriceByUserIdAndGoodsId(userSelfService.getSelfId(), goodsId, goodsNumber);
        // 计算积分
        BigDecimal integral = goodsService.getById(goodsId).getIntegral();
        if (integral == null) {
            integral = BigDecimal.ZERO;
        }
        integral=integral.multiply(BigDecimal.valueOf(goodsNumber));
        orderMoneyVO.setIntegral(integral);
        return orderMoneyVO;
    }

    @Override
    public FunctionalPayOrder generatePayOrder(GoodsGenPayOrderDTO dto) {
        // 获取用户自身id
        Long selfId = userSelfService.getSelfId();

        // 获取商品id
        Long goodsId = dto.getGoodsId();

        // 根据商品id获取商品信息
        BusWaterGoods byId = goodsService.getById(goodsId);
        // 售价*数量
        BigDecimal money = byId.getSalePrice().multiply(BigDecimal.valueOf(dto.getGoodsNumber()));

        OrderMoneyVO moneyVO = getDiscountPriceBySelf(money);
        // 生成订单描述
        String description = "【"+byId.getName()+"】 原价："+moneyVO.getOriginalMoney()+"元，折扣减免："+moneyVO.getDiscountMoney()+"元，支付金额："+moneyVO.getPayMoney()+"元";
        FunctionalPayOrder payOrder = functionalPayOrderService.generatePayOrder(
                new GeneratePayOrderDTO()
                        .setUserId(selfId)
                        .setProductCode("waterGoods")
                        .setCurrency("CNY")
                        .setAmount(moneyVO.getPayMoney())
                        .setDescription(description));

        // 初始化水产品订单，并保存至数据库
        BusWaterGoodsOrder order = initWaterGoodsOrder(dto, payOrder, moneyVO);
        order.setUserIdOfConsumer(selfId);
        repository.save(order);
        return payOrder;
    }

    @Override
    public void updateOrderPaySuccessEvent(String orderId) {
        // 根据订单id获取订单信息
        BusWaterGoodsOrder goodsOrder = repository.findByPayOrderId(Long.parseLong(orderId));
        // 如果订单信息为空，抛出异常
        if (goodsOrder == null) {
            throw new RuntimeException("订单不存在");
        }
        // 如果订单状态不是已支付状态，抛出异常
        if (!FunctionalPayOrder.STATUS_CODE_UNPAID.equals(goodsOrder.getPayOrderStatusCode())) {
            throw new RuntimeException("订单状态不是未支付状态");
        }
        // 更新订单状态为已支付状态
        // 更新支付订单状态为已支付状态
        goodsOrder.setOrderStatusCode(BusWaterGoodsOrder.ORDER_STATUS_CODE_IN_DELIVERY);
        // 更新支付订单状态为已支付状态
        goodsOrder.setPayOrderStatusCode(FunctionalPayOrder.STATUS_CODE_PAID);
        repository.save(goodsOrder);
    }

    @Override
    public void checkUnPayOrderTask() {
        // 检查30分钟未支付订单做删除动作
        List<BusWaterGoodsOrder> goodsOrders = repository.findByOrderStatusCode(BusWaterGoodsOrder.ORDER_STATUS_CODE_IN_DELIVERY);
        List<BusWaterGoodsOrder> removeOrders = goodsOrders.stream().filter(item -> System.currentTimeMillis() - item.getGmtCreate().getTime() > 1000 * 60 * 60 * 30).collect(Collectors.toList());
        repository.deleteAll(removeOrders);
    }

//    @Override
//    public void pickGoods(Long orderCode) {
//        String orderId = redisUtil.get(String.valueOf(orderCode));
//        Optional<BusWaterGoodsOrder> goodsOrder = repository.findById(Long.valueOf(orderId));
//        BusWaterGoodsOrder waterGoodsOrder = goodsOrder.orElseThrow(() -> new RuntimeException("没有查询到传入的订单Id"));
//        waterGoodsOrder.setOrderStatusCode(BusWaterGoodsOrder.ORDER_STATUS_CODE_PROVIDED);
//        repository.save(waterGoodsOrder);
//    }
//
//
//
//    @Override
//    public String generatePickCode(Long orderId) {
//        String uuid = IdUtil.simpleUUID();
//        redisUtil.setEx(uuid,String.valueOf(orderId),5, TimeUnit.MINUTES);
//        return uuid;
//    }

    /**
     * 初始化水产品订单
     * @param dto 生成支付订单的DTO
     * @param payOrder 支付订单
     * @param moneyVO 订单金额
     * @return 水产品订单
     */
    private BusWaterGoodsOrder initWaterGoodsOrder(GoodsGenPayOrderDTO dto, FunctionalPayOrder payOrder, OrderMoneyVO moneyVO) {
        // 直接将DTO转换为订单
        BusWaterGoodsOrder order = BeanUtil.copyProperties(dto, BusWaterGoodsOrder.class);

        // 提取出支付订单的id和支付状态
        order.setPayOrderId(payOrder.getId());
        // 设置出支付订单的状态编码
        order.setPayOrderStatusCode(payOrder.getStatusCode());
        // 设置商品数量
        order.setGoodsNumber(dto.getGoodsNumber());

        // 提取出moneyVO的金额信息
        // 设置原价金额
        order.setOriginalMoney(moneyVO.getOriginalMoney());
        // 设置折扣减免金额
        order.setDiscountMoney(moneyVO.getDiscountMoney());
        // 设置支付金额
        order.setPayMoney(moneyVO.getPayMoney());

        return order;
    }

    @Override
    public CountOfGoodsOrderVO getCountOfGoodsOrderSelf() {
        Long selfId = userSelfService.getSelfId();
        Long inDelivery = repository.countByUserIdOfConsumerAndOrderStatusCode(selfId, BusWaterGoodsOrder.ORDER_STATUS_CODE_IN_DELIVERY);
        Long notProvided=repository.countByUserIdOfConsumerAndOrderStatusCode(selfId,BusWaterGoodsOrder.ORDER_STATUS_CODE_NOT_PROVIDED);
        Long provided =  repository.countByUserIdOfConsumerAndOrderStatusCode(selfId,BusWaterGoodsOrder.ORDER_STATUS_CODE_PROVIDED);
        CountOfGoodsOrderVO vo = new CountOfGoodsOrderVO();
        vo.setProvidedGoodsStatusCount(provided);
        vo.setInDeliverStatusCount(inDelivery);
        vo.setNotProvidedStatusCount(notProvided);
        return vo;

    }

    @Override
    public PageResult getBodyData(PageParam<BusWaterGoodsOrderSearchOfAdminDTO> pageParam) {
        Page<BusWaterGoodsOrder> bodyData = repository.getBodyData(pageParam.getData(), pageParam.getPageable());
        return PageResult.of(bodyData);
    }

    @Override
    public PageResult getBodyDataFront(PageParam<BusWaterGoodsOrderSearchDTO> pageParam) {
        Page<BusWaterGoodsOrder> bodyDataFront = repository.getBodyDataFront(pageParam.getData(), pageParam.getPageable());
        return PageResult.of(bodyDataFront);
    }

    @Override
    public PageResult getBodyDataFrontSelf(PageParam<BusWaterGoodsOrderSearchDTO> busWaterGoodsOrder) {
        Long selfId = userSelfService.getSelfId();
        busWaterGoodsOrder.getData().setUserIdOfConsumer(selfId);
        Page<BusWaterGoodsOrder> bodyDataFront = repository.getBodyDataFront(busWaterGoodsOrder.getData(), busWaterGoodsOrder.getPageable());
        return PageResult.of(bodyDataFront);
    }

    @Override
    public void orderToNotProvided(Long orderId) {
        BusWaterGoodsOrder goodsOrder = repository.findById(orderId).orElseThrow(() -> new RuntimeException("没有查询到传入的订单Id"));
        goodsOrder.setOrderStatusCode(BusWaterGoodsOrder.ORDER_STATUS_CODE_NOT_PROVIDED);
        repository.save(goodsOrder);
    }

    @Override
    public PageResult getBodyDataFrontSelfManager(PageParam<BusWaterGoodsOrderSearchOfManageDTO> pageParam) {
        List<BusWaterLiftingPoint> selfList = liftingPointService.getSelfList();
        List<Long> liftingPointIds = new ArrayList<>();
        for (BusWaterLiftingPoint busWaterLiftingPoint : selfList) {
            liftingPointIds.add(busWaterLiftingPoint.getId());
        }
        pageParam.getData().setLiftingPointIds(liftingPointIds);
        return PageResult.of(repository.getBodyDataOfManage(pageParam.getData(), pageParam.getPageable()));
    }

    @Override
    public OrderUuidVO generatePickUuid(Long orderId) {
        // 获取用户自身id
        Long selfId = userSelfService.getSelfId();
        // 根据订单id获取订单信息
        BusWaterGoodsOrder goodsOrder = repository.findById(orderId).orElseThrow(() ->
                        BaseException.of("orderNotFound", "订单不存在")
                );
        // 如果订单状态不是已支付状态，抛出异常
        if (!FunctionalPayOrder.STATUS_CODE_PAID.equals(goodsOrder.getPayOrderStatusCode())) {
            throw BaseException.of("orderNotPaid", "订单未支付");
        }

        // 如果订单不是自己的订单，抛出异常
        if (!goodsOrder.getUserIdOfConsumer().equals(selfId)) {
            throw BaseException.of("orderNotSelf", "订单不是自己的订单");
        }

        // 生成uuid
        String uuid = IdUtil.simpleUUID();
        // 将uuid和订单id存入redis
        redisUtil.setEx("busGoodsOrder:byUuid:"+uuid, String.valueOf(orderId),33, TimeUnit.MINUTES);
        // 设置过期时间
        Long gmtExpire = System.currentTimeMillis() + 1000 * 60 * 30;

        BusWaterGoodsOrder busWaterGoodsOrder = repository.findById(orderId).orElseThrow(() ->
                BaseException.of("orderNotFound", "订单不存在")
        );


        // 返回uuid
        return new OrderUuidVO().setUuid(uuid).setGmtExpire(gmtExpire).setId(orderId).setOrder(busWaterGoodsOrder);
    }

    @Override
    public void pickGoodsByUuid(String uuid) {
        String orderIdStr = redisUtil.get("busGoodsOrder:byUuid:" + uuid);

        if (orderIdStr == null) {
            // 提示核销码过期或者不存在
            throw BaseException.of("uuidNotFound", "核销码不存在或者已过期");
        }
        Long orderId = Long.parseLong(orderIdStr);
        // 根据订单id获取订单信息
        BusWaterGoodsOrder goodsOrder = repository.findById(orderId).orElseThrow(() ->
                        BaseException.of("orderNotFound", "订单不存在")
                );

        // 判断订单是否已经提货
        if (BusWaterGoodsOrder.ORDER_STATUS_CODE_PROVIDED.equals(goodsOrder.getOrderStatusCode())) {
            // 提示订单已经提货
            throw BaseException.of("orderProvided", "订单已经提货");
        }
        // 查看订单是否是自己管辖的订单
        List<BusWaterLiftingPoint> selfList = liftingPointService.getSelfList();
        Boolean isSelfOrder = false;
        for (BusWaterLiftingPoint busWaterLiftingPoint : selfList) {
            if (busWaterLiftingPoint.getId().equals(goodsOrder.getWaterLiftingPointId())) {
                isSelfOrder = true;
                break;
            }
        }
        if (!isSelfOrder) {
            // 提示订单不在自己管理的提水点中
            throw BaseException.of("orderNotInSelfLiftingPoint", "订单不在自己管理的提水点中");
        }

        // 如果订单状态不是已支付状态，抛出异常
        if (!FunctionalPayOrder.STATUS_CODE_PAID.equals(goodsOrder.getPayOrderStatusCode())) {
            throw BaseException.of("orderNotPaid", "订单未支付");
        }
        // 将订单的状态改为已提货状态
        goodsOrder.setOrderStatusCode(BusWaterGoodsOrder.ORDER_STATUS_CODE_PROVIDED);
        // 修改核销人
        goodsOrder.setUserIdOfVerifier(userSelfService.getSelfId());

        repository.save(goodsOrder);
    }

    @Override
    public OrderUuidVO getByUuid(String uuid) {

        String orderIdStr = redisUtil.get("busGoodsOrder:byUuid:" + uuid);
        if (orderIdStr == null) {
            // 提示核销码过期或者不存在
            throw BaseException.of("uuidNotFound", "核销码不存在或者已过期");
        }
        Long orderId = Long.parseLong(orderIdStr);
        // 根据订单id获取订单信息
        BusWaterGoodsOrder goodsOrder = repository.findById(orderId).orElseThrow(() ->
                BaseException.of("orderNotFound", "订单不存在")
        );
        // 判断订单是否已经提货
        if (BusWaterGoodsOrder.ORDER_STATUS_CODE_PROVIDED.equals(goodsOrder.getOrderStatusCode())) {
            // 提示订单已经提货
            throw BaseException.of("orderProvided", "订单已经提货");
        }

        // 查看订单是否是自己管辖的订单
        List<BusWaterLiftingPoint> selfList = liftingPointService.getSelfList();
        Boolean isSelfOrder = false;
        for (BusWaterLiftingPoint busWaterLiftingPoint : selfList) {
            if (busWaterLiftingPoint.getId().equals(goodsOrder.getWaterLiftingPointId())) {
                isSelfOrder = true;
                break;
            }
        }
        if (!isSelfOrder) {
            // 提示订单不在自己管理的提水点中
            throw BaseException.of("orderNotInSelfLiftingPoint", "订单不在自己管理的提水点中");
        }

        // 如果订单状态不是已支付状态，抛出异常
        if (!FunctionalPayOrder.STATUS_CODE_PAID.equals(goodsOrder.getPayOrderStatusCode())) {
            throw BaseException.of("orderNotPaid", "订单未支付");
        }

        return new OrderUuidVO().setUuid(uuid).setId(orderId).setOrder(goodsOrder);
    }

    @Override
    public BusWaterGoodsOrder getByPayOrderId(Long payOrderId) {
        return repository.findByPayOrderId(payOrderId);
    }
}
